package com.atguigu.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.cart.feign.ProductFeignService;
import com.atguigu.cart.interceptor.CartInterceptor;
import com.atguigu.cart.service.CartService;
import com.atguigu.cart.to.UserInfoTo;
import com.atguigu.cart.vo.CartItemVo;
import com.atguigu.cart.vo.CartVo;
import com.atguigu.cart.vo.SkuInfoVo;
import com.atguigu.common.utils.R;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import static com.atguigu.common.constant.CartConstant.CART_PREFIX;

/**
 * @Author ShiJieLin
 * @Date 2022/4/26 21:53
 * @Version 1.0
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private ThreadPoolExecutor poolExecutor;

    @Override
    public void addToCart(Long skuId, Integer num) {
        // 1.获取redis对cartKey的操作链接
        BoundHashOperations<String, Object, Object> operations = getCartOps();
        // 2.判断redis中是否已经存在该商品了
        String productRedisValue = (String) operations.get(skuId.toString());
        // 3.如果为空，则调用远程服务查询商品数据
        if (StringUtils.isEmpty(productRedisValue)) {

            CartItemVo cartItemVo = new CartItemVo();
            // 异步调用
            CompletableFuture<Void> skuInfoTask = CompletableFuture.runAsync(() -> {
                // 3.1 远程调用商品服务，获取商品的信息
                R info = productFeignService.getSkuInfoBySkuId(skuId);
                if (info.getCode() == 0) {
                    SkuInfoVo skuInfo = info.getData("skuInfo", new TypeReference<SkuInfoVo>() {
                    });
                    cartItemVo.setSkuId(skuInfo.getSkuId());
                    cartItemVo.setTitle(skuInfo.getSkuTitle());
                    cartItemVo.setImage(skuInfo.getSkuDefaultImg());
                    cartItemVo.setPrice(skuInfo.getPrice());
                    cartItemVo.setCount(num);
                }
            }, poolExecutor);
            // 异步调用
            CompletableFuture<Void> skuSaleAttrTask = CompletableFuture.runAsync(() -> {
                // 3.2 获取商品的销售属性
                List<String> skuSaleAttr = productFeignService.getSkuSaleAttr(skuId);
                cartItemVo.setSkuAttrValues(skuSaleAttr);
            }, poolExecutor);

            try {
                // 等待所有的异步任务完成
                CompletableFuture.allOf(skuInfoTask, skuSaleAttrTask).get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            // 将数据存储到redis中
            String cartItemJson = JSON.toJSONString(cartItemVo);
            operations.put(skuId.toString(), cartItemJson);
        } else {
            // 4. 如果redis中有数据，那么只需要修改数量即可
            CartItemVo cartItemVo = JSON.parseObject(productRedisValue, CartItemVo.class);
            cartItemVo.setCount(cartItemVo.getCount() + num);
            // 修改redis的数据
            String cartItemJson = JSON.toJSONString(cartItemVo);
            operations.put(skuId.toString(), cartItemJson);
        }
    }

    @Override
    public CartItemVo getCartItem(Long skuId) {
        // 拿到要操作的购物车信息
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        // 获取redis中的购物车数据
        String redisValue = (String) cartOps.get(skuId.toString());
        CartItemVo cartItemVo = JSON.parseObject(redisValue, CartItemVo.class);

        return cartItemVo;
    }

    @Override
    public CartVo getAllCartItem() {

        CartVo cartVo = new CartVo();
        // 1.获取用户信息
        UserInfoTo userInfoTo = CartInterceptor.toThreadLocal.get();
        // 判断用户是否登陆
        if (null != userInfoTo.getUserId()) {
            // 2.如果用户已经登陆，合并用户购物车 和 临时购物车
            // 用户登陆的key 和 临时用户key
            String cartKey = CART_PREFIX + userInfoTo.getUserId();
            String tempUserKey = CART_PREFIX + userInfoTo.getUserKey();
            // 2.1获取临时购物车中的数据
            List<CartItemVo> tempCartItemVos = getCartItemVos(tempUserKey);
            if(null != tempCartItemVos && tempCartItemVos.size() > 0){
                for (CartItemVo itemVo : tempCartItemVos) {
                    addToCart(itemVo.getSkuId(), itemVo.getCount());
                }
                // 清除临时购物车中的数据
                clearCartInfo(tempUserKey);
            }
            // 2.2获取登陆后的购物车数据
            List<CartItemVo> cartItemVos = getCartItemVos(cartKey);
            cartVo.setItems(cartItemVos);
        } else {
            // 3.如果用户没有登陆
            String cartKey = CART_PREFIX + userInfoTo.getUserKey();
            List<CartItemVo> itemVoList = getCartItemVos(cartKey);
            cartVo.setItems(itemVoList);
        }
        return cartVo;
    }

    @Override
    public void clearCartInfo(String cartKey) {
        redisTemplate.delete(cartKey);
    }

    @Override
    public List<CartItemVo> getCurrentCartItems() {
        // 1.获取用户登陆信息
        UserInfoTo userInfoTo = CartInterceptor.toThreadLocal.get();
        List<CartItemVo> cartItemVoList;

        if(null != userInfoTo && null != userInfoTo.getUserId()){
            // 2.获取用户购物车存redis的数据
            String cartKey = CART_PREFIX + userInfoTo.getUserId();
            // 3.获取存在redis中的购物车数据
            List<CartItemVo> cartItemVos = getCartItemVos(cartKey);

            cartItemVoList = cartItemVos.stream().filter((item) -> item.getCheck())
                    .collect(Collectors.toList());
            /** 这里雷神讲的是：要重新查询购物车的价格
             *  个人认为可以在用户点击购物车的时候，重新查询商品信息(价格，库存)
             */
            return cartItemVoList;
        }else {
            return null;
        }
    }

    /**
     * 根据 cartKey获取购物车中的所有商品数据
     *
     * @param cartKey user-key 或者 用户id
     * @return
     */
    private List<CartItemVo> getCartItemVos(String cartKey) {

        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(cartKey);
        List<Object> values = hashOps.values();

        if (null != values && values.size() > 0) {

            List<CartItemVo> itemVoList = values.stream().map((obj) -> {
                String cartTemp = (String) obj;
                CartItemVo cartItemVo = JSON.parseObject(cartTemp, CartItemVo.class);
                return cartItemVo;
            }).collect(Collectors.toList());
            return itemVoList;
        }
        return null;
    }


    private BoundHashOperations<String, Object, Object> getCartOps() {
        // 1.获取用户信息
        UserInfoTo userInfoTo = CartInterceptor.toThreadLocal.get();
        // 2.根据拦截器中的用户信息判断是 登陆用户 Or 临时用户
        String cartKey = "";
        if (null != userInfoTo.getUserId()) {
            cartKey = CART_PREFIX + userInfoTo.getUserId();
        } else {
            cartKey = CART_PREFIX + userInfoTo.getUserKey();
        }
        /** 绑定指定Key对redis进行操作
         *  后续所有的操作都是对同一个key进行操作
         */
        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
        return operations;
    }


}
